Skip to content

feat(web): opt-in X-Forwarded-For keying for the rate limiter behind a trusted proxy#156

Merged
Liohtml merged 1 commit into
mainfrom
claude/dependabot-prs-q6u94z
Jul 10, 2026
Merged

feat(web): opt-in X-Forwarded-For keying for the rate limiter behind a trusted proxy#156
Liohtml merged 1 commit into
mainfrom
claude/dependabot-prs-q6u94z

Conversation

@Liohtml

@Liohtml Liohtml commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Summary

The in-memory rate limiter (#110) keyed on the client socket IP. Behind a reverse proxy — the deployment SECURITY.md/README recommend for network exposure — every request carries the proxy's IP, collapsing all clients into one shared bucket: a single noisy client exhausts the limit for everyone.

Fixes #142

Changes

  • src/medcheck/core/config.py: new Settings.trust_proxy_headers (MEDCHECK_TRUST_PROXY_HEADERS, off by default)
  • src/medcheck/web/app.py: _client_key() — uses the first X-Forwarded-For hop as the rate-limit key only when the flag is set; falls back to the socket IP when the header is absent. Off by default because the header is client-spoofable without a trusted proxy (and would then allow trivial limiter bypass — covered by a test)
  • SECURITY.md: documents the flag and that the proxy's own rate limiting should remain the primary control in proxied deployments (the in-process limiter is per-worker)
  • README.md + .env.example: document MEDCHECK_TRUST_PROXY_HEADERS
  • tests/unit/test_web.py: 3 new tests — spoofed header ignored by default (no bypass), distinct forwarded clients get distinct buckets when trusted, missing header falls back to socket IP

Testing

  • Existing tests pass (uv run pytest) — 200 passed
  • New tests added for new functionality — 3 new web tests
  • Coverage does not decrease (uv run pytest --cov-fail-under=85) — 90.25%
  • Linting passes (uv run ruff check .)
  • Type checking passes (uv run mypy src/medcheck --strict)
  • Pre-commit hooks pass — ruff hooks pass locally; full pre-commit not run

🤖 Generated with Claude Code

https://claude.ai/code/session_01W4svt5QTs4WUMSy4HwiVt9


Generated by Claude Code

…a trusted proxy

The in-memory limiter keyed on the client socket IP. Behind a reverse
proxy — the documented deployment for network exposure — every request
carries the proxy's IP, collapsing all clients into one shared bucket:
one noisy client exhausts the limit for everyone. New opt-in setting
MEDCHECK_TRUST_PROXY_HEADERS uses the first X-Forwarded-For hop as the
bucket key. Off by default because the header is client-spoofable
without a trusted proxy in front (and would then allow limiter bypass).
SECURITY.md documents that the proxy's own limiter should remain the
primary control in proxied deployments.

Fixes #142

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W4svt5QTs4WUMSy4HwiVt9
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@Liohtml, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 14 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9372e047-24d5-4e60-9659-36844ae673e8

📥 Commits

Reviewing files that changed from the base of the PR and between f0357f1 and 48faf1b.

📒 Files selected for processing (6)
  • .env.example
  • README.md
  • SECURITY.md
  • src/medcheck/core/config.py
  • src/medcheck/web/app.py
  • tests/unit/test_web.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/dependabot-prs-q6u94z

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@Liohtml Liohtml merged commit b4b032e into main Jul 10, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[repo-health] Low: Rate limiter keys on socket IP — behind the documented reverse-proxy deployment all clients share one bucket

2 participants